#include "DXUT.h"
#include "ImportanceSampling2D.h"
#include <time.h>


ImportanceSampling2D::ImportanceSampling2D(void):m_p2DDataArray(NULL),m_iDataWidth(0),m_iDataHeight(0),m_p1DDistrib_x(NULL),m_bDataIsReady(false)
{
}


ImportanceSampling2D::~ImportanceSampling2D(void)
{
	SAFE_DELETE_ARRAY(m_p2DDataArray);
	SAFE_DELETE(m_p1DDistrib_x);
	for (size_t i = 0; i < m_p1DDistrib_y.GetSize(); i++)
		SAFE_DELETE(m_p1DDistrib_y[i]);
	m_p1DDistrib_y.RemoveAll();
}

void ImportanceSampling2D::SetNewDataArrSize(size_t iHeight, size_t iWidth)
{
	m_iDataHeight = iHeight;
	m_iDataWidth = iWidth;
	SAFE_DELETE_ARRAY(m_p2DDataArray);
	m_p2DDataArray = new float(m_iDataHeight*m_iDataWidth);
}

void ImportanceSampling2D::Initialize2DData(size_t iHeight, size_t iWidth)
{
	if(iHeight!=m_iDataHeight&&iWidth!=m_iDataWidth)
		SetNewDataArrSize(iHeight,iWidth);

	 srand( (unsigned)time( NULL ) );
	for (size_t i =0 ; i < m_iDataWidth; i++)
		for (size_t j = 0; j < m_iDataHeight; j++)
			m_p2DDataArray[j+m_iDataHeight*i] = (float)rand()/RAND_MAX;

}


bool ImportanceSampling2D::Create2DDistributions()
{
	if(m_iDataWidth==0||m_iDataHeight==0||!m_bDataIsReady)
		return false;

	SAFE_DELETE(m_p1DDistrib_x);
	for (size_t i = 0; i < m_p1DDistrib_y.GetSize(); i++)
		SAFE_DELETE(m_p1DDistrib_y[i]);
	m_p1DDistrib_y.RemoveAll();

	float *func = new float(MAX(m_iDataHeight, m_iDataWidth));
	float *sinVals = new float(m_iDataHeight);

	for (unsigned int i = 0; i < m_iDataHeight; ++i)
		sinVals[i] = sin(D3DX_PI * float(i+.5)/float(m_iDataHeight));

	for (unsigned int u = 0; u < m_iDataWidth; ++u) {
		// Compute sampling distribution for column _u_
		for (unsigned int v = 0; v < m_iDataHeight; ++v)
			func[v] = m_p2DDataArray[v+u*m_iDataHeight] *= sinVals[v];
		Distribution1D* pDis = new Distribution1D(func,m_iDataHeight);
		m_p1DDistrib_y.Add(pDis);
	}
	// Compute sampling distribution for columns of image
	for (unsigned int u = 0; u < m_iDataWidth; ++u)
		func[u] = m_p1DDistrib_y[u]->funcInt;
	m_p1DDistrib_x = new Distribution1D(func, m_iDataWidth);

	SAFE_DELETE_ARRAY(func);
	SAFE_DELETE_ARRAY(sinVals);

	return true;
}

D3DXVECTOR2 ImportanceSampling2D::SampleData(const D3DXVECTOR2& uv)
{
	//test code
	float pdfs[2];
	float fu = m_p1DDistrib_x->Sample(uv.x, &pdfs[0]);
	int u = (int)floor(fu);
	if (u < 0) u = 0;
	if (u > m_p1DDistrib_x->count-1) u = m_p1DDistrib_x->count-1;
	float fv = m_p1DDistrib_y[u]->Sample(uv.y, &pdfs[1]);
	int v = (int)floor(fv);

	return D3DXVECTOR2(u,v);
}